# coding=utf-8

import os
from typing import List

from generator.excle.apvp_net_excle import gen_apvp_interface_excle
from generator.libapvp.Common import gen_ipcp_common_h
from generator.libapvp.IPCPSignalManager import gen_IPCPSignalManager
from generator.libapvp.Android_bp import gen_apvp_Android_bp
from generator.libapvp.NetIPCP import gen_net_ipcp_main
from generator.libapvp.PACBPropertyImpl import gen_PACBDirectTransmitPropertyImpl
from generator.libapvp.ProtoBuf import gen_APVPProtoBuf
from generator.libapvp.SHAREELEMENT import gen_share_version_h
from generator.libapvp.SignalPropertyImpl import gen_SignalDirectTransmitPropertyImpl
from generator.libapvp.SignalServiceId import gen_ServiceIdHeadFile
from generator.libapvp.convertSignalFromIPCPValue import generateSignalFromIPCP2Value
from generator.libapvp.convertSignalToIPCPValue import generateSignalToIPCPValue
from generator.libapvp.gen_rx_package_h import gen_rx_package_h
from generator.libapvp.mcu_heads import generateECUHeadFile
from generator.libapvp.signal_id import gen_SignalIdHeadFile
from generator.libapvp.validate import gen_Validate
from generator.libapvp.CarConfigToSystemProperties import gen_CCToSystemPropertiesImpl
from generator.types_hal.property import Property, TypesHal
from parse.carconfig_parse import parseCarConfig
from parse.cb_pa_parse import genCBPAUtils, parseCBPAExcle
from parse.parse_types import  Module
from parse.sdb_parser import ECU, SDBParser
from parse.timeout_parser import TimeoutParser

from utils.util import copyPackageTo, removeDir
from generator.libapvp.WireShark_ipcp_lua import gen_ipcp_object


class APVP:

    def __init__(self) -> None:
        # 信号集合
        self.ecus: List[ECU] = []
        # CBPA模块集合
        self.modules: List[Module] = []
        self.directionTransmits: List[str]=[]
        self.carconfig:ECU = None
        self.carconfigThousand:ECU = None


class APVPParser:
    def __init__(self, dir: str) -> None:
        self.__cbpa_dir=os.path.join(dir,"ipcp/cbpa")
        self.__timeout_dir=os.path.join(dir,"ipcp/sdb")
        self.__library_name="libapvp"
        self.__libaray_proto_name = "{}-proto".format(self.__library_name)
        self.__out_proto_dir="./data/transfer/libapvp/proto"
        self.__genertor_path="./data/transfer/{}".format(self.__library_name)
        self.__out_path = "../transfer/{}".format(self.__library_name)
        self.apvp: APVP = APVP()

    def parse(self,directionTransmits:List[str]):
        sdbParser=SDBParser()
        sdbParser.parse()
        (carconfig,carconfigThousand,enums) = parseCarConfig()
        for enum in enums:
            sdbParser.sdb.textTables[enum.getTypeName()] = enum
        timeoutParser=TimeoutParser()
        timeoutParser.parse(self.__timeout_dir)
        modules = parseCBPAExcle(
            self.__cbpa_dir, sdbParser.sdb.textTables)
        self.apvp.carconfig = carconfig
        self.apvp.carconfigThousand = carconfigThousand
        self.apvp.ecus.extend(sdbParser.sdb.ecus)
        self.apvp.ecus.append(carconfig)
        self.apvp.ecus.append(carconfigThousand)
        self.apvp.ecus.append(timeoutParser.ecu)
        self.apvp.modules.extend(modules)
        self.apvp.directionTransmits.extend(directionTransmits)

    def genertor_files(self):
        removeDir(self.__genertor_path)
        generateECUHeadFile(self.apvp.ecus,self.__genertor_path)
        generateSignalFromIPCP2Value(self.apvp.ecus,self.__genertor_path)
        generateSignalToIPCPValue(self.apvp.ecus,self.__genertor_path)
        genCBPAUtils(self.apvp.modules,self.__genertor_path)
        gen_share_version_h(self.__genertor_path)

        gen_ServiceIdHeadFile(self.apvp.ecus, self.apvp.modules,self.__genertor_path)
        gen_SignalIdHeadFile(self.apvp.ecus, self.apvp.modules,self.__genertor_path)
        gen_Validate(self.apvp.ecus, self.apvp.modules,self.__genertor_path)
        gen_rx_package_h(self.__genertor_path)
        gen_ipcp_common_h(self.__genertor_path)

        gen_net_ipcp_main(self.__genertor_path)
        gen_IPCPSignalManager(self.apvp.ecus, self.apvp.modules,self.__genertor_path)
        #gen_CCToSystemPropertiesImpl(self.apvp.carconfig,self.apvp.carconfigThousand)
        gen_apvp_Android_bp(self.__library_name,self.__genertor_path)
        gen_APVPProtoBuf(self.apvp.modules, self.apvp.ecus, self.apvp.directionTransmits,self.__out_proto_dir,self.__libaray_proto_name)
        gen_apvp_interface_excle(self.apvp.ecus, self.apvp.modules)
        gen_ipcp_object(self.apvp.ecus, self.apvp.modules, self.__genertor_path)
        copyPackageTo(self.__genertor_path, self.__out_path)

    def genertorDirectTransmitImpl(self)-> TypesHal:
        typesHal = TypesHal()
        names = []
        for ecu in self.apvp.ecus:
            #print("zpy genertorDirectTransmitImpl ecu:", ecu.name)
            for signal in ecu.rxPackage.signals:
                #print("zpy genertorDirectTransmitImpl signal:", signal.name)
                if signal.name in self.apvp.directionTransmits:
                    #print("zpy genertorDirectTransmitImpl rxsignal:", signal.name)
                    property = Property(signal.name, True)
                    property.setAccessMode("READ")
                    property.setChangeMode("ON_CHANGE")
                    property.setPropArea("GLOBAL")
                    property.setPropType(signal.toPropType())
                    property.setDesc("none")
                    property.setPublisher(ecu.name)
                    property.setSubscriber("IHU")

                    if signal.hasEnum():
                        encodeType = signal.getEncodeType()
                        property.setEncodeType(encodeType.getTypeName())
                        if encodeType.isEnum() and encodeType.getTypeName() not in names:
                            names.append(encodeType.getTypeName())
                            typesHal.addEnum(encodeType)
                    else:
                        property.setEncodeType(
                            signal.getValueType().name)
                    typesHal.addProperty(property)
            for txSignal in ecu.txSignals:
                if txSignal.name in self.apvp.directionTransmits:
                    #print("zpy genertorDirectTransmitImpl txSignal:", txSignal.name)
                    property = Property(txSignal.name, True)
                    property.setAccessMode("WRITE")
                    property.setChangeMode("ON_CHANGE")
                    property.setPropArea("GLOBAL")
                    property.setPropType(txSignal.toPropType())
                    property.setDesc("none")
                    property.setPublisher("IHU")
                    property.setSubscriber(ecu.name)
                    if txSignal.isSingle():
                        signal = txSignal.signals[0]
                        if signal.hasEnum():
                            encodeType = signal.getEncodeType()
                            property.setEncodeType(encodeType.getTypeName())
                            if encodeType.isEnum() and encodeType.getTypeName() not in names:
                                names.append(encodeType.getTypeName())
                                typesHal.addEnum(encodeType)
                        else:
                            property.setEncodeType(
                                signal.getValueType().name)
                    typesHal.addProperty(property)

        for module in self.apvp.modules:
            for pa in module.pa_apis:
                if pa.api in self.apvp.directionTransmits:
                    #print("zpy genertorDirectTransmitImpl paSignal:", pa.api)
                    property = Property(pa.api, True)
                    property.setAccessMode("READ")
                    property.setChangeMode("ON_CHANGE")
                    property.setPropArea("GLOBAL")
                    property.setPropType(pa.getTypesHalType())
                    property.setDesc("none" if pa.desc == "" else pa.desc)
                    property.setPublisher(module.name)
                    property.setSubscriber("IHU")

                    if pa.getPayload().isStructPayload():
                        structPayload = pa.getPayload().getStructPayload()
                        for member in structPayload.members:
                            if member.hasEncodeType() and member.getEncodeType().isEnum():
                                encodeType = member.getEncodeType()
                                property.setEncodeType(
                                    encodeType.getTypeName())
                                if encodeType.getTypeName() not in names:
                                    names.append(encodeType.getTypeName())
                                    typesHal.addEnum(encodeType)
                        typesHal.addProperty(property)
            for cb in module.cb_apis:
                if cb.api in self.apvp.directionTransmits:
                    #print("zpy genertorDirectTransmitImpl cbSignal:", cb.api)
                    property = Property(cb.api, True)
                    property.setAccessMode("WRITE")
                    property.setChangeMode("ON_CHANGE")
                    property.setPropArea("GLOBAL")
                    property.setPropType(cb.getTypesHalType())
                    property.setDesc("none" if cb.desc == "" else cb.desc)
                    property.setPublisher("IHU")
                    property.setSubscriber(module.name)

                    if cb.getPayload().isBaseTypePayload():
                        basePayload = cb.getPayload().getBaseTypePayload()
                        if basePayload.hasEncodeType() and basePayload.getEncodeType().isEnum():
                            encodeType = basePayload.getEncodeType()
                            property.setEncodeType(encodeType.getTypeName())
                            if encodeType.getTypeName() not in names:
                                names.append(encodeType.getTypeName())
                                typesHal.addEnum(encodeType)
                    else:
                        if cb.getPayload().isArrayPayload():
                            property.setEncodeType(cb.getPayload().getArrayPayload().array_type.name+"[{}]".format(
                                cb.getPayload().getArrayPayload().array_len
                            ))
                        else:
                            property.setEncodeType(
                                cb.getPayload().getStructPayload().type_name)
                    typesHal.addProperty(property)
        self.__toDirectTransmitImpl(self.apvp.directionTransmits)
        return typesHal

    def __toDirectTransmitImpl(self, directTransmitList: List[str]):
        directTransmitSignals = []
        directTransmitTXSignals = []
        for ecu in self.apvp.ecus:
            for signal in ecu.rxPackage.signals:
                if signal.name in directTransmitList:
                    #print("zpy __toDirectTransmitImpl rxSignal:", signal.name)
                    directTransmitSignals.append(signal)
            for tx in ecu.txSignals:
                if tx.name in directTransmitList:
                    #print("zpy __toDirectTransmitImpl txSignal:", tx.name)
                    directTransmitTXSignals.append(tx)


        directTransmitPA = []
        directTransmitCB = []
        for module in self.apvp.modules:
            for pa in module.pa_apis:
                if pa.api in directTransmitList:
                    #print("zpy __toDirectTransmitImpl paSignal:", pa.api)
                    directTransmitPA.append(pa)
            for cb in module.cb_apis:
                if cb.api in directTransmitList:
                    #print("zpy __toDirectTransmitImpl cbSignal:", cb.api)
                    directTransmitCB.append(cb)
        gen_SignalDirectTransmitPropertyImpl(
            directTransmitSignals, directTransmitTXSignals)
        #print("zpy gen_SignalDirectTransmitPropertyImpl write /vhal_platform/directTransmit/*.cpp (RX&TX)")   
        gen_PACBDirectTransmitPropertyImpl(directTransmitPA, directTransmitCB)
        #print("zpy gen_SignalDirectTransmitPropertyImpl write /vhal_platform/directTransmit/*.cpp (PA&CB)") 
